#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Auth: 张宇飞(zhangyufei49@163.com)
Date: 2017-10-18
Desc: 用于转换tick 和 time
"""

def _tick2time(tick, tempo, beat_type, tpq):
    """
    系数 x 每一拍是多长的物理时间 x 一共多少拍
    """
    return (beat_type / 4.0) * (60.0 / tempo) * (tick / float(tpq))

def _time2tick(time, tempo, beat_type, tpq):
    """
    按照上面 _tick2time 进行变化得到
    """
    return (time * tpq * 4.0 * tempo) / (beat_type * 60.0)

class TickTime(object):
    def __init__(self, tpq = 480):
        super(TickTime, self).__init__()
        self.tempos = []
        self.tpq = 480

    def add_tempo(self, tick, tempo, beat_type = 4):
        """
        添加一个节拍变化的时间点
        : tick      : 发生节拍变化的时间点
        : tempo     : 变化后的节拍
        : beat_type : 节拍类型 4 , 8 , 2 这种，表示以几分之一小节为一拍
        """
        if tick < 0 or (type(tick) != int):
            print('参数 tick 有误')
            return False
        if tempo < 1 or (type(tempo) != int):
            print('参数 tempo 有误')
            return False

        if beat_type < 1 or (type(beat_type) != int):
            print('参数 beat_type 有误')
            return False

        for t in self.tempos:
            if t['tick'] == tick:
                print('已经添加过 tick 值为 %d 的节拍信息' % tick)
                return False

        item = {
                "tick": tick,
                "tempo": tempo,
                "beat_type": beat_type,
        }
        self.tempos.append(item)
        # 默认就会使用 tick 排序
        self.tempos.sort(key = lambda x:x["tick"])
        return True

    def del_tempo(self, tick):
        """
        删除一个节拍变化信息
        : tick : 要删除的那个变化节拍的 tick 值
        """
        for t in self.tempos:
            if t['tick'] == tick:
                self.tempos.remove(t)
                return
        print('没有找到 tick 为 %d 的变拍信息' % tick)

    def clr_tempo(self):
        """
        清除所有的节拍信息
        """
        self.tempos = []

    def list_tempo(self):
        """
        打印节拍变化的时间点
        """
        l = len(self.tempos)
        if l == 0:
            print('tempo 列表为空')
            return

        for i in xrange(l):
            tempo = self.tempos[i]
            print('[%04d] tick = %-10d tempo = %-4d beat type = 1/%d' % (i, tempo["tick"], tempo["tempo"], tempo["beat_type"]))

    def time(self, tick):
        """
        转换 tick 到 time
        : return : -1 转换失败。其它表示秒数
        """
        if tick < 0 or (len(self.tempos) == 0):
            return -1

        time, last_tick, tpq = 0, 0, self.tpq
        t = self.tempos[0]
        cur_tick, tempo, beat_type = t["tick"], t["tempo"], t["beat_type"]
        for t in self.tempos[1:]:
            cur_tick = t["tick"]
            if cur_tick >= tick:
                break
            time += _tick2time(cur_tick - last_tick, tempo, beat_type, tpq)
            tempo, beat_type = t["tempo"], t["beat_type"]
            last_tick = cur_tick

        return time + _tick2time(tick - last_tick, tempo, beat_type, tpq)

    def tick(self, time):
        """
        转换 time 到 tick
        : return : -1 表示失败。其它表示 tick 值
        """
        if time < 0 or (len(self.tempos) == 0):
            return -1

        cur_time, last_time, last_tick, tpq = 0, 0, 0, self.tpq
        t = self.tempos[0]
        cur_tick, tempo, beat_type = t["tick"], t["tempo"], t["beat_type"]
        for t in self.tempos[1:]:
            cur_tick = t["tick"]
            cur_time += _tick2time(cur_tick - last_tick, tempo, beat_type, tpq)

            if cur_time >= time:
                break

            last_tick, tempo, beat_type = cur_tick, t["tempo"], t["beat_type"]
            last_time = cur_time

        return int(last_tick + _time2tick(time - last_time, tempo, beat_type, tpq) + 0.00005)
